﻿using Lanbt.Core.Entity;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.IdentityModel.Tokens;
using System.ComponentModel;
using System.IdentityModel.Tokens.Jwt;
using System.Reflection;
using System.Reflection.PortableExecutable;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;

namespace Lanbt.Core.Utility.Helper
{
    /// <summary>
    /// JWT帮助类
    /// </summary>
    public class JwtHelper
    {
        /// <summary>
        /// 生成JWT Token
        /// </summary>
        /// <param name="claims"></param>
        /// <param name="startTime">创建时间</param>
        /// <param name="expTime">过期时间（默认10小时后过期）</param>
        /// <returns></returns>
        public static string CreateToken(Claim[] claims, DateTime startTime, DateTime expTime)
        {
            // 2. 从 appsettings.json 中读取SecretKey
            var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(GlobalContext.SystemConfig.SecreKey));

            // 3. 选择加密算法
            var algorithm = SecurityAlgorithms.HmacSha256;

            // 4. 生成Credentials
            var signingCredentials = new SigningCredentials(secretKey, algorithm);

            if (startTime == DateTime.MinValue)
            {
                startTime = DateTime.Now;
            }

            if (expTime == DateTime.MinValue)
            {
                expTime = startTime.AddHours(10);
            }

            // 5. 根据以上，生成token
            var jwtSecurityToken = new JwtSecurityToken(
                GlobalContext.SystemConfig.Issuer,     //Issuer
                GlobalContext.SystemConfig.Audience,   //Audience
                claims,                           //Claims,
                startTime,                        //notBefore  从当前时间算
                expTime,                          //expires 经过10小时过期
                signingCredentials                //Credentials
            );

            // 6. 将token变为string
            var token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);

            return token;
        }

        /// <summary>
        /// 获取token信息
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public static CurrentUser VerificationToken(string token)
        {
            Type type = typeof(CurrentUser);
            //var currentUser = Activator.CreateInstance(type);//反射创建对象
            var currentUser = new CurrentUser();
            try
            {
                var jwtClaims = new JwtSecurityTokenHandler().ReadJwtToken(token);

                //验证Token是否过期
                var start = new DateTime(1970, 1, 1, 0, 0, 0);
                var nowDate = DateTime.Now;
                var nbf = Convert.ToInt64(jwtClaims.Claims.First(x => x.Type == "nbf").Value);//创建时间
                var nbfDate = start.AddSeconds(nbf).ToLocalTime();
                var exp = Convert.ToInt64(jwtClaims.Claims.First(x => x.Type == "exp").Value);//过期时间
                var expDate = start.AddSeconds(exp).ToLocalTime();
                if (nowDate > expDate)
                {
                    currentUser.IsError = true;
                    currentUser.ErrorMsg = "JWT Token过期";
                    return currentUser;
                }
                //验证发布人
                var iss = jwtClaims.Claims.First(x => x.Type == "iss").Value;//发布地址
                if (iss != GlobalContext.SystemConfig.Issuer)
                {
                    currentUser.IsError = true;
                    currentUser.ErrorMsg = "JWT Issuer 验证失败";
                    return currentUser;
                }
                //验证接收人
                var aud = jwtClaims.Claims.First(x => x.Type == "aud").Value;//接收地址
                if (aud != GlobalContext.SystemConfig.Audience)
                {
                    currentUser.IsError = true;
                    currentUser.ErrorMsg = "JWT Audience验证失败";
                    return currentUser;
                }

                currentUser.Id = jwtClaims.Claims.First(x => x.Type == "Id").Value;
                currentUser.UserName = jwtClaims.Claims.First(x => x.Type == "UserName").Value;
                currentUser.Name = jwtClaims.Claims.First(x => x.Type == "Name").Value;

                //验证ScurityKey
                var claims = new[]
                {
                    new Claim("UserName", currentUser.UserName),
                    new Claim("Name", currentUser.Name),
                    new Claim("Id", currentUser.Id),
                };
                if (token != CreateToken(claims, nbfDate, expDate))
                {
                    currentUser.IsError = true;
                    currentUser.ErrorMsg = "JWT ScurityKey密钥验证失败";
                    return currentUser;
                }

                return currentUser;
            }
            catch
            {
                currentUser.IsError = true;
                currentUser.ErrorMsg = "Token解析失败";
                return currentUser;
            }
        }

    }
}
